#include <signal.h>
#include <sys/socket.h>
#include "Config.h"
#include "WorkSvr.h"
#include "SvrMemBlock.h"
#include "PkgBufMgr.h"

#define SERVER_CRT "server.crt"
#define SERVER_KEY "server.key"
#define RECV_BUFFER_MAX 2048

CWorkSvr::CWorkSvr()
{
    m_ilfd = -1;
    m_pbm = nullptr;
    m_ctxSvr = nullptr;
}

CWorkSvr::~CWorkSvr()
{
    Destroy();
}

bool CWorkSvr::Init(int *fds)
{
    bool bRet = false;
    bRet = CServer::Init(fds);

    if (!bRet)
        return false;

    // 获得监听端口
    m_ilfd = CSvrMgr::GetInstance()->GetListenSocket();

    if (-1 == m_ilfd)
        return false;

    m_pbm = CPkgBufMgr::GetInstance();

    if (nullptr == m_pbm)
    {
        Destroy();
        return false;
    }

    // 绑定监听端口,绑定m_ilfd到epoll,ev.data.ptr 为 m_ilfd 地址
    bRet = UpdateEvents(m_ilfd, EPOLLIN | EPOLLET | EPOLLEXCLUSIVE, EPOLL_CTL_ADD, &m_ilfd);

    if (!bRet)
    {
        Destroy();
        printf("Error epoll_ctl:\tfile=%s\tline=%d\n", __FILE__, __LINE__);
        return false;
    }

    if (CConfig::bUseSsl)
    {
        int iRet = 0;
        // 返回值判断
        SSL_library_init();
        SSL_load_error_strings();
        SSLeay_add_ssl_algorithms();
        OpenSSL_add_all_algorithms();
        m_ctxSvr = SSL_CTX_new(SSLv23_server_method());

        if (nullptr == m_ctxSvr)
        {
            Destroy();
            printf("Error SSL_CTX_new\n");
            return false;
        }

        SSL_CTX_set_verify(m_ctxSvr, SSL_VERIFY_NONE, nullptr);
        iRet = SSL_CTX_load_verify_locations(m_ctxSvr, "ca.crt", nullptr);

        if (0 >= iRet)
        {
            Destroy();
            printf("Error SSL_CTX_load_verify_locations:\tiRet=%d\n", iRet);
            return false;
        }

        iRet = SSL_CTX_use_certificate_file(m_ctxSvr, SERVER_CRT, SSL_FILETYPE_PEM);

        if (0 >= iRet)
        {
            Destroy();
            printf("Error SSL_CTX_use_certificate_file:\tiRet=%d\n", iRet);
            return false;
        }

        iRet = SSL_CTX_use_certificate_chain_file(m_ctxSvr, SERVER_CRT);

        if (0 >= iRet)
        {
            Destroy();
            printf("Error SSL_CTX_use_certificate_chain_file\n");
            return false;
        }

        iRet = SSL_CTX_use_PrivateKey_file(m_ctxSvr, SERVER_KEY, SSL_FILETYPE_PEM);

        if (0 >= iRet)
        {
            Destroy();
            printf("Error SSL_CTX_use_PrivateKey_file\n");
            return false;
        }

        iRet = SSL_CTX_check_private_key(m_ctxSvr);

        if (0 >= iRet)
        {
            Destroy();
            printf("Error SSL_CTX_check_private_key\n");
            return false;
        }
    }

    // 让ClientNode可获得所属WorkSvr实例
    // m_lstClnt.SetExtData(this);

    return true;
}

// bool CWorkSvr::Start()
// {
//     return true;
// }

bool CWorkSvr::Stop()
{
    if (-1 != m_ilfd)
        UpdateEvents(m_ilfd, 0, EPOLL_CTL_DEL, nullptr);

    return CServer::Stop();
}

bool CWorkSvr::Destroy()
{
    CServer::Destroy();
    m_lstClnt.Destroy();

    if (nullptr != m_ctxSvr)
    {
        SSL_CTX_free(m_ctxSvr);
        m_ctxSvr = nullptr;
    }

    if (nullptr != m_pbm)
    {
        m_pbm->Destroy();
        delete m_pbm;
        m_pbm = nullptr;
    }

    return true;
}

bool CWorkSvr::ErrorEvent(epoll_event &ee)
{
    if (&m_ilfd == ee.data.ptr)
    {
        kill(0, SIGINT);
        return false;
    }
    else if (nullptr != ee.data.ptr)
    {
        printf("Disconnect pid=%d client=%p\n", getpid(), ee.data.ptr);
        DestroyClient((CClient *)ee.data.ptr);
    }

    return true;
}

bool CWorkSvr::InputEvent(epoll_event &ee)
{
    bool bRet = false;

    if (&m_ilfd == ee.data.ptr)
    {
        bRet = AcceptEvent();
    }
    else if (nullptr != ee.data.ptr)
    {
        bRet = RecvHandle((CClient *)ee.data.ptr);
    }

    return bRet;
}

bool CWorkSvr::OutputEvent(epoll_event &ee)
{
    bool bRet = false;

    if (nullptr != ee.data.ptr)
    {
        bRet = SendHandle((CClient *)ee.data.ptr);
    }

    return bRet;
}

bool CWorkSvr::IpcCmdEvent(IpcPkgBuf &pbRecv)
{
    bool bRet = false;

    switch (pbRecv.cmdIpc)
    {
    case IpcCmd::Accept:
        bRet = AcceptHandle();
        break;

    case IpcCmd::SendData:
        bRet = IpcSendData(pbRecv);
        break;

    case IpcCmd::DataHandle:
        bRet = IpcDataHandle(pbRecv);
        break;

    default:
        printf("Error IpcCmd:\tfile=%s\tline=%d\n", __FILE__, __LINE__);
        break;
    }

    return bRet;
}

bool CWorkSvr::AcceptEvent()
{
    bool bRet = false;

    if (0 == m_lstClnt.GetSize())
    {
        bRet = AcceptHandle();
    }
    else
    {
        CSvrMgr *pSvrMgr = CSvrMgr::GetInstance();
        CWorkSvr *pWorkSvr = pSvrMgr->GetAcceptServer();

        if (nullptr == pWorkSvr)
            return false;

        if (pWorkSvr == this)
        {
            bRet = AcceptHandle();
        }
        else
        {
            int iRet = 0;
            IpcCmdMsg msg;
            int iSize = (int)sizeof(msg);

            msg.len = sizeof(IpcCmd);
            msg.cmd = IpcCmd::Accept;
            iRet = pWorkSvr->IpcSend(&msg, iSize);

            if (iRet >= iSize)
                bRet = true;
        }
    }

    return bRet;
}

bool CWorkSvr::AcceptHandle()
{
    int icfd;
    struct sockaddr sa;
    socklen_t sl = sizeof(sockaddr);

    while (true)
    {
        icfd = accept(m_ilfd, &sa, &sl);

        if (-1 == icfd)
        {
            if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
                break;
            else
            {
                printf("Error accept:\terror=%d\tfile=%s\tline=%d\n", errno, __FILE__, __LINE__);
                return false;
            }
        }
        else
        {
            CClient *pClnt = nullptr;

            if (!SetNonBlock(icfd))
            {
                printf("Error (!SetNonBlock(icfd)):\terror=%d\tfile=%s\tline=%d\n", errno, __FILE__, __LINE__);
                return false;
            }

            pClnt = CreateClient(icfd);

            if (nullptr == pClnt)
                return false;
        }
    }

    return true;
}

bool CWorkSvr::RecvHandle(CClient *pClnt)
{
    int iRecv = 0;
    HandleResult hr = HandleResult::Error;

    // 仅有一个地方调用该函数，已判断是否为空
    // if (nullptr == pClnt)
    //     return false;

    iRecv = pClnt->Recv();

    if (0 < iRecv)
    {
        do
        {
            hr = pClnt->DataHandle();

            switch (hr)
            {
            case HandleResult::Success:
                if (!pClnt->HasRecvData())
                    hr = HandleResult::Fail;
                break;

            case HandleResult::Error:
                DestroyClient(pClnt);
                break;

            default:
                break;
            }
        } while (HandleResult::Success == hr);
    }
    else if (-1 == iRecv)
    {
        DestroyClient(pClnt);
    }

    return true;
}

bool CWorkSvr::SendHandle(CClient *pClnt)
{
    int iSent = 0;

    if (nullptr == pClnt)
        return false;

    if (pClnt->HasSendData())
    {
        iSent = pClnt->Send();

        if (-1 == iSent)
            DestroyClient(pClnt);
    }

    return true;
}

CClient *CWorkSvr::CreateClient(int ifd)
{
    bool bRet = false;
    ClientNode *pNode = (ClientNode *)m_lstClnt.NewNode();

    if (nullptr == pNode)
        return nullptr;

    bRet = pNode->Init(ifd, this, m_ctxSvr, m_pBufMgr);

    if (!bRet)
        return nullptr;

    bRet = m_lstClnt.PushBack(pNode);

    if (!bRet)
    {
        m_lstClnt.DeleteNode(pNode);
        return nullptr;
    }

    UpdateEvents(ifd, EPOLLIN | EPOLLOUT | EPOLLET, EPOLL_CTL_ADD, pNode);

    return (CClient *)pNode;
}

void CWorkSvr::DestroyClient(CClient *pClnt)
{
    int ifd = -1;

    if (nullptr == pClnt)
        return;

    ifd = pClnt->GetSocket();
    UpdateEvents(ifd, 0, EPOLL_CTL_DEL, nullptr);
    m_lstClnt.Remove((ClientNode *)pClnt);
    m_lstClnt.DeleteNode((ClientNode *)pClnt);
}

// IPC数据处理，直接转发其它客户端通过IPC发过来的数据
bool CWorkSvr::IpcSendData(IpcPkgBuf &pbRecv)
{
    int iSent = 0;
    uint16_t nHead = 0;
    uint16_t nNeedSend = 0;
    ClientNode *pNode = *(ClientNode **)(pbRecv.pBuffer);

    if (nullptr == pNode)
    {
        printf("Error: IpcSendData line=%d\n", __LINE__);
        return false;
    }

    // 判断是否为本服务的客户端
    if (&m_lstClnt != pNode->Belong())
    {
        printf("Error: IpcSendData line=%d\n", __LINE__);
        return false;
    }

    nHead = sizeof(ClientNode *);

    // 没有数据
    if (pbRecv.nPkgLen <= nHead)
    {
        printf("Error: IpcSendData line=%d\n", __LINE__);
        return false;
    }

    nNeedSend = pbRecv.nPkgLen - nHead;
    iSent = pNode->SendPackage(pbRecv.pBuffer + nHead, nNeedSend);

    return (iSent == nNeedSend);
}

// IPC数据处理，其它客户端发给本进程的客户端进行数据处理，不发送到终端
bool CWorkSvr::IpcDataHandle(IpcPkgBuf &pbRecv)
{
    uint16_t nHead = 0;
    uint16_t nHandle = 0;
    ClientNode *pNode = *(ClientNode **)(pbRecv.pBuffer);

    if (nullptr == pNode)
    {
        printf("Error: IpcDataHandle line=%d\n", __LINE__);
        return false;
    }

    // 判断是否为本服务的客户端
    if (&m_lstClnt != pNode->Belong())
    {
        printf("Error: IpcDataHandle line=%d\n", __LINE__);
        return false;
    }

    nHead = sizeof(ClientNode *);

    // 没有数据
    if (pbRecv.nPkgLen <= nHead)
    {
        printf("Error: IpcDataHandle line=%d\n", __LINE__);
        return false;
    }

    nHandle = pbRecv.nPkgLen - nHead;

    return pNode->IpcDataHandle(pbRecv.pBuffer + nHead, nHandle);
}